package shark.permission.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.stereotype.Service;
import shark.common.utils.oConvertUtils;
import shark.permission.model.SysPermissionTree;
import shark.permission.service.ISysPermissionService;
import shark.permission.spi.entity.SysPermission;
import shark.permission.spi.mapper.SysPermissionMapper;
import shark.permission.spi.mapper.SysRolePermissionMapper;
import shark.user.spi.entity.SysRole;
import shark.user.spi.mapper.SysRoleMapper;

import javax.annotation.Resource;
import java.util.*;

@Service
public class ISysPermissionServiceImpl  extends ServiceImpl<SysPermissionMapper, SysPermission> implements ISysPermissionService {

    @Resource
    private SysPermissionMapper sysPermissionMapper;

    @Resource
    private SysRolePermissionMapper sysRolePermissionMapper;

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Override
    public List<SysPermissionTree> queryListByParentId(String parentId) {
        List<SysPermission> list = sysPermissionMapper.selectList(
                new LambdaQueryWrapper<SysPermission>()
                        .eq(SysPermission::getDelFlag, 0)
                        .eq(SysPermission::getId, parentId));
        List<SysPermission> all = sysPermissionMapper.selectList(
                new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getDelFlag, 0));
        List<SysPermission> result = new ArrayList<>();

        for (SysPermission sysPermission:list){
            this.getChild(all, sysPermission.getId(), result);
        }
        result.addAll(list);

        return getTree(result);
    }

    @Override
    public void deletePermission(String id) {
        SysPermission sysPermission = this.getById(id);
        if(sysPermission==null) {
            log.error("未找到菜单信息");
        }
        String pid = sysPermission.getParentId();
        if(oConvertUtils.isNotEmpty(pid)) {
            int count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, pid));
            if(count==1) {
                //若父节点无其他子节点，则该父节点是叶子节点
                this.sysPermissionMapper.setMenuLeaf(pid, 1);
            }
        }
        sysPermissionMapper.deleteById(id);
        // 该节点可能是子节点但也可能是其它节点的父节点,所以需要级联删除
        this.removeChildrenBy(sysPermission.getId());
        //关联删除
        Map map = new HashMap<>();
        map.put("permission_id",id);
        //删除角色授权表
        sysRolePermissionMapper.deleteByMap(map);
    }

    @Override
    public void deletePermissionLogical(String id) {
        List<SysPermission> list = sysPermissionMapper.selectList(
                new LambdaQueryWrapper<SysPermission>()
                        .eq(SysPermission::getDelFlag, 0)
                        .eq(SysPermission::getId, id));
         List<SysPermission> permissions = new ArrayList<>();
         this.getChild(list, id, permissions);
         permissions.addAll(list);

         for (SysPermission sysPermission : permissions) {
             sysPermission.setDelFlag(1);
         }

         this.updateBatchById(permissions);
    }

    @Override
    public void addPermission(SysPermission sysPermission) {
        if("0".equals(sysPermission.getMenuType())) {
            sysPermission.setParentId(null);
        }
        String pid = sysPermission.getParentId();
        if(oConvertUtils.isNotEmpty(pid)) {
            //设置父节点不为叶子节点
            sysPermissionMapper.setMenuLeaf(pid, 0);
        }
        sysPermission.setCreateTime(new Date());
        sysPermission.setDelFlag(0);
        sysPermission.setLeaf(true);
        this.save(sysPermission);
    }

    @Override
    public void editPermission(SysPermission sysPermission) {
        SysPermission p = this.getById(sysPermission.getId());
        //TODO 该节点判断是否还有子节点
        if(p==null) {
            log.error("未找到菜单信息");
        }else {
            sysPermission.setUpdateTime(new Date());
            //Step1.判断是否是一级菜单，是的话清空父菜单ID
            if("0".equals(sysPermission.getMenuType())) {
                sysPermission.setParentId("");
            }
            //Step2.判断菜单下级是否有菜单，无则设置为叶子节点
            int count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, sysPermission.getId()));
            if(count==0) {
                sysPermission.setLeaf(true);
            }
            this.updateById(sysPermission);

            //如果当前菜单的父菜单变了，则需要修改新父菜单和老父菜单的，叶子节点状态
            String pid = sysPermission.getParentId();
            if((oConvertUtils.isNotEmpty(pid) && !pid.equals(p.getParentId())) || oConvertUtils.isEmpty(pid)&&oConvertUtils.isNotEmpty(p.getParentId())) {
                //a.设置新的父菜单不为叶子节点
                this.sysPermissionMapper.setMenuLeaf(pid, 0);
                //b.判断老的菜单下是否还有其他子菜单，没有的话则设置为叶子节点
                int cc = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, p.getParentId()));
                if(cc==0) {
                    if(oConvertUtils.isNotEmpty(p.getParentId())) {
                        this.sysPermissionMapper.setMenuLeaf(p.getParentId(), 1);
                    }
                }

            }
        }
    }

    @Override
    public Map<String, List<SysPermission>> getAuthorize() {
        List<Map<String, Object>> maps = sysPermissionMapper.getAuthorize();
        List<SysRole> roles = sysRoleMapper.selectList(new LambdaQueryWrapper<>());
        return toMapResource(maps, roles);
    }

    @Override
    public List<SysPermission> queryByUser(String username) {
        return this.sysPermissionMapper.queryByUser(username);
    }

    @Override
    public List<SysPermissionTree> queryTreeByUser(String username) {
        List<SysPermission> list = sysPermissionMapper.queryByUser(username);
        return getTree(list);
    }

    @Override
    public boolean hasPermission(String username, SysPermission sysPermission) {
        int count = baseMapper.queryCountByUsername(username,sysPermission);
        if(count>0){
            return true;
        }else{
            return false;
        }
    }

    @Override
    public boolean hasPermission(String username, String url) {
        SysPermission sysPermission = new SysPermission();
        sysPermission.setUrl(url);
        int count = baseMapper.queryCountByUsername(username,sysPermission);
        if(count>0){
            return true;
        }else{
            return false;
        }
    }

    private List<SysPermissionTree> getTree(List<SysPermission> permissions) {
        List<SysPermissionTree> root = new ArrayList<>();
        List<SysPermissionTree> tree = new ArrayList<>();

        for (SysPermission sysPermission : permissions) {
            if (sysPermission.getParentId() == null || "".equals(sysPermission.getParentId())) {
                root.add(new SysPermissionTree(sysPermission));
            } else {
                tree.add(new SysPermissionTree(sysPermission));
            }
        }

        getChildDepart(root, tree);
        setEmptyChildrenAsNull(root);
        if (root.size() == 0) {
            return tree;
        }
        return root;
    }

    private void getChildDepart (List<SysPermissionTree> root, List<SysPermissionTree> tree) {
        for (int i = 0; i<root.size(); i++) {
            SysPermissionTree rootBranch =root.get(i);
            for (int j = 0; j<tree.size(); j++) {
                SysPermissionTree node = tree.get(j);
                if (node.getParentId() != null && node.getParentId().equals(rootBranch.getId())) {
                    rootBranch.getChildren().add(node);
                }
            }
            if (rootBranch.getChildren() != null) {
                getChildDepart(rootBranch.getChildren(),tree);
            }
        }
    }

    private void setEmptyChildrenAsNull(List<SysPermissionTree> tree){
        for (int i = 0; i < tree.size(); i++) {
            SysPermissionTree model = tree.get(i);
            if (model.getChildren().size() == 0) {
                model.setChildren(null);
                model.setIsLeaf(true);
            }else{
                setEmptyChildrenAsNull(model.getChildren());
                model.setIsLeaf(false);
            }
        }
    }

    private void getChild(List<SysPermission> all, String pid, List<SysPermission> result) {
        for (SysPermission depart : all) {
            if (pid.equals(depart.getParentId())) {
                getChild(all, depart.getId(), result);
                result.add(depart);
            }
        }
    }

    public Map<String, List<SysPermission>> toMapResource(List<Map<String, Object>> resources, List<SysRole> roles) {
        Map<String, List<SysPermission>> authorizeMap = new HashMap<>();
        for (SysRole role : roles) {
            List<SysPermission> list = new ArrayList<>();
            for (Map<String, Object> resource : resources) {
                if (role.getId().equals(resource.get("role_id"))) {
                    SysPermission r = mapToResource(resource);
                    list.add(r);
                }
            }
            authorizeMap.put(role.getRoleCode(), list);
        }
        return authorizeMap;
    }

    private SysPermission mapToResource(Map<String, Object> resourceMap) {
        SysPermission permission = new SysPermission();
        permission.setId((String) resourceMap.get("id"));
        permission.setParentId((String) resourceMap.get("parent_id"));
        permission.setName((String) resourceMap.get("name"));
        permission.setMenuType((Integer) resourceMap.get("menu_type"));
        permission.setUrl((String) resourceMap.get("url"));
        return permission;
    }

    private void removeChildrenBy(String parentId) {
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<>();
        // 封装查询条件parentId为主键,
        query.eq(SysPermission::getParentId, parentId);
        // 查出该主键下的所有子级
        List<SysPermission> permissionList = this.list(query);
        if (permissionList != null && permissionList.size() > 0) {
            String id = ""; // id
            int num = 0; // 查出的子级数量
            // 如果查出的集合不为空, 则先删除所有
            this.remove(query);
            // 再遍历刚才查出的集合, 根据每个对象,查找其是否仍有子级
            for (int i = 0, len = permissionList.size(); i < len; i++) {
                id = permissionList.get(i).getId();
                Map map = new HashMap<>();
                map.put("permission_id",id);
                //删除角色授权表
                sysRolePermissionMapper.deleteByMap(map);
                num = this.count(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getParentId, id));
                // 如果有, 则递归
                if (num > 0) {
                    this.removeChildrenBy(id);
                }
            }
        }
    }
}
